"""
数据库连接监控模块
定期测试数据库连接状态，提供连接健康检查
"""

import threading
import time
import logging
from typing import Dict, Optional, Callable
from datetime import datetime, timedelta
from concurrent.futures import ThreadPoolExecutor, as_completed

from src.database.connection_manager import db_manager
from config.database_config import db_config_manager
from src.utils.config_storage import config_storage


class ConnectionMonitor:
    """数据库连接监控器"""
    
    def __init__(self, check_interval: int = 300):  # 默认5分钟检查一次
        self.check_interval = check_interval  # 检查间隔（秒）
        self.logger = logging.getLogger(__name__)
        self.is_running = False
        self.monitor_thread = None
        self.connection_status: Dict[str, Dict] = {}
        self.status_callbacks = []
        self.lock = threading.RLock()
    
    def add_status_callback(self, callback: Callable):
        """添加状态变化回调函数"""
        self.status_callbacks.append(callback)
    
    def start_monitoring(self):
        """开始监控"""
        if self.is_running:
            self.logger.warning("连接监控已在运行中")
            return
        
        self.is_running = True
        self.monitor_thread = threading.Thread(target=self._monitoring_loop, daemon=True)
        self.monitor_thread.start()
        self.logger.info(f"连接监控已启动，检查间隔: {self.check_interval}秒")
    
    def stop_monitoring(self):
        """停止监控"""
        self.is_running = False
        if self.monitor_thread and self.monitor_thread.is_alive():
            self.monitor_thread.join(timeout=5)
        self.logger.info("连接监控已停止")
    
    def _monitoring_loop(self):
        """监控主循环"""
        while self.is_running:
            try:
                self._check_all_connections()
                
                # 等待下次检查
                for _ in range(self.check_interval):
                    if not self.is_running:
                        break
                    time.sleep(1)
                    
            except Exception as e:
                self.logger.error(f"连接监控循环出错: {str(e)}")
                time.sleep(10)  # 出错后等待10秒再继续
    
    def _check_all_connections(self):
        """检查所有数据库连接"""
        configs = db_config_manager.list_configs()
        if not configs:
            return
        
        self.logger.debug(f"开始检查 {len(configs)} 个数据库连接")
        
        # 并发检查连接
        with ThreadPoolExecutor(max_workers=5) as executor:
            future_to_name = {
                executor.submit(self._check_single_connection, name): name 
                for name in configs.keys()
            }
            
            for future in as_completed(future_to_name):
                config_name = future_to_name[future]
                try:
                    result = future.result()
                    self._update_connection_status(config_name, result)
                except Exception as e:
                    self.logger.error(f"检查连接 {config_name} 时出错: {str(e)}")
                    self._update_connection_status(config_name, {
                        "success": False,
                        "error": str(e),
                        "check_time": datetime.now()
                    })
    
    def _check_single_connection(self, config_name: str) -> Dict:
        """检查单个数据库连接"""
        start_time = time.time()
        
        try:
            success = db_manager.test_connection(config_name)
            response_time = (time.time() - start_time) * 1000  # 转换为毫秒
            
            result = {
                "success": success,
                "response_time": round(response_time, 2),
                "check_time": datetime.now(),
                "error": None
            }
            
            if success:
                self.logger.debug(f"连接 {config_name} 正常，响应时间: {response_time:.2f}ms")
            else:
                self.logger.warning(f"连接 {config_name} 失败")
                result["error"] = "连接测试失败"
            
            return result
            
        except Exception as e:
            response_time = (time.time() - start_time) * 1000
            error_msg = str(e)
            
            self.logger.error(f"连接 {config_name} 检查出错: {error_msg}")
            
            return {
                "success": False,
                "response_time": round(response_time, 2),
                "check_time": datetime.now(),
                "error": error_msg
            }
    
    def _update_connection_status(self, config_name: str, result: Dict):
        """更新连接状态"""
        with self.lock:
            old_status = self.connection_status.get(config_name, {}).get("success")
            self.connection_status[config_name] = result
            
            # 更新存储的测试结果
            config_storage.update_connection_test_result(
                config_name, 
                result["success"], 
                result.get("error")
            )
            
            # 如果状态发生变化，通知回调函数
            if old_status is not None and old_status != result["success"]:
                status_text = "连接恢复" if result["success"] else "连接断开"
                self.logger.info(f"数据库 {config_name} 状态变化: {status_text}")
                
                for callback in self.status_callbacks:
                    try:
                        callback(config_name, result)
                    except Exception as e:
                        self.logger.error(f"状态回调执行失败: {str(e)}")
    
    def get_connection_status(self, config_name: str = None) -> Dict:
        """获取连接状态"""
        with self.lock:
            if config_name:
                return self.connection_status.get(config_name, {})
            return self.connection_status.copy()
    
    def get_connection_summary(self) -> Dict:
        """获取连接状态摘要"""
        with self.lock:
            total = len(self.connection_status)
            online = sum(1 for status in self.connection_status.values() if status.get("success", False))
            offline = total - online
            
            # 计算平均响应时间
            response_times = [
                status.get("response_time", 0) 
                for status in self.connection_status.values() 
                if status.get("success", False)
            ]
            avg_response_time = sum(response_times) / len(response_times) if response_times else 0
            
            return {
                "total": total,
                "online": online,
                "offline": offline,
                "avg_response_time": round(avg_response_time, 2),
                "last_check": max(
                    (status.get("check_time", datetime.min) for status in self.connection_status.values()),
                    default=None
                )
            }
    
    def force_check(self, config_name: str = None) -> Dict:
        """强制检查指定连接或所有连接"""
        if config_name:
            # 检查单个连接
            result = self._check_single_connection(config_name)
            self._update_connection_status(config_name, result)
            return {config_name: result}
        else:
            # 检查所有连接
            self._check_all_connections()
            return self.get_connection_status()
    
    def is_connection_healthy(self, config_name: str, max_age_minutes: int = 10) -> bool:
        """检查连接是否健康"""
        status = self.get_connection_status(config_name)
        if not status:
            return False
        
        # 检查连接是否成功
        if not status.get("success", False):
            return False
        
        # 检查检查时间是否太旧
        check_time = status.get("check_time")
        if check_time:
            age = datetime.now() - check_time
            if age > timedelta(minutes=max_age_minutes):
                return False
        
        return True


# 全局连接监控器实例
connection_monitor = ConnectionMonitor()